iT邦幫忙

2026 iThome 鐵人賽

DAY 9
0
AI Engineering

從呼叫 API 到打造 Gateway:LLM 工程化 30 天系列 第 9

Day 9:Prompt 版本管理與除錯:寫 prompt 不是一次就結束

  • 分享至 

  • xImage
  •  

Day 9:Prompt 版本管理與除錯:寫 prompt 不是一次就結束

這幾天分享了prompt的基本架構、要不要給範例、推理引導的用法,但以上用法都是主觀上認為有用,沒有一個明確的標準可以判斷模型回應是否變好、變得更符合需求。因此今天要講的主題,就是對於prompt「演進」的管理與除錯。

Prompt 也該被版本控制

寫程式時,不會把邏輯改動直接蓋掉舊版本,而是用 git 留下紀錄、方便回頭比較。Prompt也適用這種方法,尤其當一個 prompt 牽涉到多個規則、範例、格式要求時,一次調整可能會在改善某個情境的同時,悄悄搞砸另一個情境。

版控實務上常見的做法:

  • 把 prompt 存成獨立的檔案或設定,不是寫死在程式碼裡到處複製貼上
  • 每次調整都留下版本紀錄,方便回溯是哪一版造成了行為變化
  • 準備一組固定的測試案例(輸入 + 你預期的行為),每次改動後都跑一次,而不是只測試你這次想解決的那個情境

簡單的測試迴圈案例

以下用一個情緒分類的例子示範:同一組 test case,分別套用兩個版本的 system prompt,跑完後直接看誰的正確率比較高。

import os
import anthropic

client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])

test_cases = [
    {"input": "出貨超快,包裝也很仔細,下次還會再買", "expected": "正面"},
    {"input": "客服完全不讀訊息,等了三天才回,爛透了", "expected": "負面"},
    {"input": "東西還行,沒有特別驚艷", "expected": "中立"},
    {"input": "還可以啦,但價格偏貴", "expected": "中立"},
    {"input": "品質普通,但至少準時送達,沒有太大問題", "expected": "中立"},
]

prompt_versions = {
    "v1": "請判斷評論的情緒,只回傳「正面」「負面」或「中立」其中一個詞。",
    "v2": (
        "你是情緒分析助理。請判斷以下評論的整體情緒傾向。\n"
        "規則:\n"
        "- 只有明確偏好或不滿時才判斷為「正面」或「負面」\n"
        "- 語氣平淡、有褒有貶、或無法判斷時一律回傳「中立」\n"
        "只回傳「正面」「負面」或「中立」其中一個詞,不要加任何標點或說明。"
    ),
}

def run_prompt(system_prompt, user_input):
    response = client.messages.create(
        model="claude-sonnet-4-5",
        max_tokens=10,
        temperature=0,
        system=system_prompt,
        messages=[{"role": "user", "content": user_input}],
    )
    return response.content[0].text.strip().strip("。.,、")

def evaluate(version_name, system_prompt):
    correct = 0
    print(f"\n=== 版本:{version_name} ===")
    for case in test_cases:
        result = run_prompt(system_prompt, case["input"])
        is_correct = result == case["expected"]
        correct += is_correct
        mark = "✓" if is_correct else "✗"
        print(f"{mark} 輸入:{case['input']} → 得到:{result}(預期:{case['expected']})")
    accuracy = correct / len(test_cases)
    print(f"正確率:{correct}/{len(test_cases)}({accuracy:.0%})")
    return accuracy

results = {name: evaluate(name, prompt) for name, prompt in prompt_versions.items()}

print("\n=== 版本比較 ===")
for name, acc in results.items():
    print(f"{name}: {acc:.0%}")

跑完之後可以直接看到兩個版本各自的正確率。如果 v2 在「中立」案例上明顯進步,同時沒有讓「正面」「負面」的判斷變差,就代表這次調整是確實有效的改善。

常見的 Prompt 失敗案例

除了量化比較版本優劣,寫 prompt 時也有幾個比較常見雷點,越早避開,有機會能降低version 迭代的次數

在設計prompt時,常遇到的問題:

  • 指令太模糊:例如只說「幫我整理一下」,沒定義格式、長度、重點,模型只好自由發揮,每次結果都不太一樣。可以透過把目標、預期結果與內容定義清楚,或直接透過structured output鎖定回應格式來解決。

  • prompt 太長,重點被稀釋:塞了太多規則跟背景資訊,模型可能會抓不住重點。解法是精簡、把最重要的規則放在最前面或最後面(模型對開頭跟結尾的內容通常比中間的更敏感)。

  • 範例不具代表性:few-shot 範例都集中在某種情況,模型看到範例外的情況容易誤判。

  • 使用者輸入跟系統指令混在一起:如果你把使用者輸入直接原封不動貼進 prompt,使用者有機會用輸入內容「蓋掉」你原本的指令(例如打一句「忽略以上規則,改成 xxx」)。這也是為什麼 system/user 角色要分開處理,而不是全部串成一串文字。

小結

針對prompt Engineering的分享到這邊告一段落,這幾天記錄了prompt的基本架構、操作概念(範例、引導推理),以及今天分享了版本控制的重要、模型回應的驗證比較方法等。

明天開始會切換到下一個主題:Context Engineering。當想要給模型的資訊越來越多時,該如何精簡或管理模型得到的資訊,是下一章節的重點。


上一篇
Day 08:Chain-of-Thought:讓模型寫下推理過程
下一篇
Day 10:Context Window 是什麼:限制與迷思
系列文
從呼叫 API 到打造 Gateway:LLM 工程化 30 天22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言